<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover"/>
<meta name="description" content="A diagram that does not scroll or zoom and has a fixed area in which to move parts."/> 
<link rel="stylesheet" href="../assets/css/style.css"/> 
<!-- Copyright 1998-2021 by Northwoods Software Corporation. -->
<title>Absolute positioning within the viewport</title>
</head>

<body>
  <!-- This top nav is not part of the sample code -->
  <nav id="navTop" class="w-full z-30 top-0 text-white bg-nwoods-primary">
    <div class="w-full container max-w-screen-lg mx-auto flex flex-wrap sm:flex-nowrap items-center justify-between mt-0 py-2">
      <div class="md:pl-4">
        <a class="text-white hover:text-white no-underline hover:no-underline
        font-bold text-2xl lg:text-4xl rounded-lg hover:bg-nwoods-secondary " href="../">
          <h1 class="mb-0 p-1 ">GoJS</h1>
        </a>
      </div>
      <button id="topnavButton" class="rounded-lg sm:hidden focus:outline-none focus:ring" aria-label="Navigation">
        <svg fill="currentColor" viewBox="0 0 20 20" class="w-6 h-6">
          <path id="topnavOpen" fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM9 15a1 1 0 011-1h6a1 1 0 110 2h-6a1 1 0 01-1-1z" clip-rule="evenodd"></path>
          <path id="topnavClosed" class="hidden" fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path>
        </svg>
      </button>
      <div id="topnavList" class="hidden lg:text-base sm:block items-center w-auto mt-0 text-white p-0 z-20">
        <ul class="list-reset list-none font-semibold flex justify-end flex-wrap sm:flex-nowrap items-center px-0 pb-0">
          <li class="p-1 sm:p-0"><a class="topnav-link" href="../learn/">Learn</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="../samples/">Samples</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="../intro/">Intro</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="../api/">API</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/products/register.html">Register</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="../download.html">Download</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="https://forum.nwoods.com/c/gojs/11">Forum</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/contact.html"
           target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/contact.html', 'contact');">Contact</a></li>
          <li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/sales/index.html"
           target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/sales/index.html', 'buy');">Buy</a></li>
        </ul>
      </div>
    </div>
    <hr class="border-b border-gray-600 opacity-50 my-0 py-0" />
  </nav>
  <div class="md:flex flex-col md:flex-row md:min-h-screen w-full max-w-screen-xl mx-auto">
    <div id="navSide" class="flex flex-col w-full md:w-48 text-gray-700 bg-white flex-shrink-0"></div>
    <!-- * * * * * * * * * * * * * -->
    <!-- Start of GoJS sample code -->
    
    <script src="../release/go.js"></script>
    <div class="p-4 w-full">
<script id="code">
  function init() {
    if (window.goSamples) goSamples();  // init for these samples -- you don't need to call this
    var $ = go.GraphObject.make;

    myDiagram =
      $(go.Diagram, "myDiagramDiv",
        {
          fixedBounds: new go.Rect(0, 0, 500, 300),  // document is always 500x300 units
          allowHorizontalScroll: false,  // disallow scrolling or panning
          allowVerticalScroll: false,
          allowZoom: false,              // disallow zooming
          "animationManager.isEnabled": false,
          "undoManager.isEnabled": true,
          "ModelChanged": function(e) {     // just for demonstration purposes,
            if (e.isTransactionFinished) {  // show the model data in the page's TextArea
              document.getElementById("mySavedModel").textContent = e.model.toJson();
            }
          }
        });

    // the background Part showing the fixed bounds of the diagram contents
    myDiagram.add(
      $(go.Part,
        { layerName: "Grid", position: myDiagram.fixedBounds.position },
        $(go.Shape, { fill: "oldlace", strokeWidth: 0, desiredSize: myDiagram.fixedBounds.size })
      ));

    // This function is the Node.dragComputation, to limit the movement of the parts.
    function stayInFixedArea(part, pt, gridpt) {
      var diagram = part.diagram;
      if (diagram === null) return pt;
      // compute the document area without padding
      var v = diagram.documentBounds.copy().subtractMargin(diagram.padding);
      // get the bounds of the part being dragged
      var bnd = part.actualBounds;
      var loc = part.location;
      // now limit the location appropriately
      var l = v.x + (loc.x - bnd.x);
      var r = v.right - (bnd.right - loc.x);
      var t = v.y + (loc.y - bnd.y);
      var b = v.bottom - (bnd.bottom - loc.y);
      if (l <= gridpt.x && gridpt.x <= r && t <= gridpt.y && gridpt.y <= b) return gridpt;
      var p = gridpt.copy();
      if (diagram.toolManager.draggingTool.isGridSnapEnabled) {
        // find a location that is inside V but also keeps the part's bounds within V
        var cw = diagram.grid.gridCellSize.width;
        if (cw > 0) {
          while (p.x > r) p.x -= cw;
          while (p.x < l) p.x += cw;
        }
        var ch = diagram.grid.gridCellSize.height;
        if (ch > 0) {
          while (p.y > b) p.y -= ch;
          while (p.y < t) p.y += ch;
        }
        return p;
      } else {
        p.x = Math.max(l, Math.min(p.x, r));
        p.y = Math.max(t, Math.min(p.y, b));
        return p;
      }
    }

    myDiagram.nodeTemplate =
      $(go.Node, "Auto",
        { dragComputation: stayInFixedArea },
        // get the size from the model data
        new go.Binding("desiredSize", "size", go.Size.parse),
        // get and set the position in the model data
        new go.Binding("position", "pos", go.Point.parse).makeTwoWay(go.Point.stringify),
        // temporarily put selected nodes in Foreground layer
        new go.Binding("layerName", "isSelected", function(s) { return s ? "Foreground" : ""; }).ofObject(),
        $(go.Shape, "Rectangle",
          { strokeWidth: 0 },  // avoid extra thickness from the stroke
          new go.Binding("fill", "color")),
        $(go.TextBlock,
          new go.Binding("text", "color"))
      );

    myDiagram.model = new go.GraphLinksModel([
      { "key": "Alpha", "pos": "0 0", "size": "50 50", "color": "lightblue" },
      { "key": "Beta", "pos": "276 19", "size": "100 100", "color": "orange" },
      { "key": "Gamma", "pos": "44 214", "size": "100 50", "color": "lightgreen" },
      { "key": "Delta", "pos": "239 171", "size": "50 100", "color": "pink" }
    ],
      [
        { from: "Alpha", to: "Beta" },
        { from: "Alpha", to: "Gamma" },
        { from: "Gamma", to: "Delta" },
        { from: "Delta", to: "Alpha" }
      ]);
  }
  window.addEventListener('DOMContentLoaded', init);
</script>

  <div id="sample">
    <div id="myDiagramDiv" style="width:100%; height:400px"></div>
    <p>
      Absolute positioning within the viewport, with no scrolling (or panning) or zooming allowed.
    </p>
    <p>
      There is a special colored background Part that shows the fixed area where Parts may be.
      It is in the "Grid" Layer so that it is not selectable and is always behind the regular Parts.
    </p>
    <p>
      Parts may not be dragged outside of the fixed document area of the diagram.
      This is implemented by a custom <a>Part.dragComputation</a> function.
    </p>
    <p>
      Note that the user may still scroll or zoom the whole page.
    </p>
    <p>The model data, automatically updated after each change or undo or redo:</p>
    <textarea id="mySavedModel" style="width:100%;height:250px"></textarea>
  </div>
    </div>
    <!-- * * * * * * * * * * * * * -->
    <!--  End of GoJS sample code  -->
  </div>
</body>
<!--  This script is part of the gojs.net website, and is not needed to run the sample -->
<script src="../assets/js/goSamples.js"></script>
</html>
